﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.IO;
using System.Diagnostics;

namespace System.Data.DataSetGenerator
{
    public class SqlGeneratorFacade : IMessageSender
    {
        public SqlGeneratorFacade(TypedDataSetGeneratorConfiguration configuration)
        {
            if (configuration == null)
                throw new ArgumentNullException("configuration");

            this.Configuration = configuration;
        }

        public TypedDataSetGeneratorConfiguration Configuration { get; private set; }

        public void Run()
        {
            SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(Configuration.ConnectionString);
            csb.MultipleActiveResultSets = true;

            using (SqlConnection connection = new SqlConnection(csb.ConnectionString))
            {
                SendMessage("Connection String OK", TraceLevel.Info);

                connection.Open();
                SendMessage("Connected to " + csb.DataSource, TraceLevel.Info);

                // Execute the DataSet Generators
                foreach (DataSetDescriptor dataSetDescriptor in Configuration.DataSets)
                {
                    String message = String.Format("{0}: processing... ", dataSetDescriptor.DataSetName);
                    SendMessage(message, TraceLevel.Info);

                    if (Configuration.DataSetsToInclude.Count != 0 &&
                        !Configuration.DataSetsToInclude.Contains(dataSetDescriptor.DataSetName))
                        goto __NEXT;
                    SqlTypedDataSetGenerator generator = new SqlTypedDataSetGenerator(connection, dataSetDescriptor, Configuration.Language);
                    generator.Message += new MessageEventHandler(OnMessage);
                    generator.Run();

                __NEXT: ;
                }

                // Execute the DAL (DataAdapters) Generators
                if (Configuration.DataAdapters != null && Configuration.DataAdapters.GenerateDataAdapters)
                {
                    String daFileName = String.IsNullOrEmpty(Configuration.DataAdapters.DataAdaptersFileName) ? "DataAdapters.cs" : Configuration.DataAdapters.DataAdaptersFileName;
                    FileUtil.ClearReadOnlyFlag(daFileName);
                    using (FileStream daFileStream = new FileStream(daFileName, FileMode.Create))
                    {
                        daFileStream.Position = 0;
                        StreamWriter writer = new StreamWriter(daFileStream);
                        writer.WriteLine("using System;");
                        writer.WriteLine("using System.Data;");
                        writer.WriteLine("using System.Linq;");
                        writer.WriteLine("using System.Data.SqlClient;");
                        writer.WriteLine("");

                        if (!String.IsNullOrEmpty(Configuration.DataAdapters.DataAdaptersNamespace))
                            writer.WriteLine("namespace " + Configuration.DataAdapters.DataAdaptersNamespace + "{");

                        writer.Flush();

                        ColumnFilter columnFilter = new ColumnFilter();
                        columnFilter.IgnoreComputedColumns = true;

                        var tableNames = Util.GetTableNames(connection);
                        foreach (var tableName in tableNames)
                        {
                            DataAdapterDescriptor descriptor = new DataAdapterDescriptor();
                            Util.CloneProperties(Configuration.DataAdapters, descriptor);
                            descriptor.TableName = tableName;

                            SqlDataAdapterGenerator daGenerator = new SqlDataAdapterGenerator(connection, descriptor);
                            daGenerator.Message += new MessageEventHandler(OnMessage);
                            daGenerator.WriteCode(daFileStream);
                        }

                        if (!String.IsNullOrEmpty(Configuration.DataAdapters.DataAdaptersNamespace))
                            writer.WriteLine("}");
                        writer.Flush();

                        SendMessage("DataAdapters have been saved to " + daFileName, TraceLevel.Info);
                    }
                }
            }
        }

        void OnMessage(object sender, MessageEventArgs eargs)
        {
            SendMessage(eargs.Message, eargs.TraceLevel); 
        }

        private void SendMessage(String message, TraceLevel level)
        {
            if (Message != null)
            {
                MessageEventArgs e = new MessageEventArgs(message, level);
                Message(this, e);
            }
        }

        #region IMessageSender Members

        public event MessageEventHandler Message;

        #endregion
    }
}
